﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using System.Diagnostics;

namespace Chromium_Updater
{
    public delegate void updateAvailable(bool updateAvailable, AppUpdate[] availableUpdates);

    public partial class UpdaterForm : Form
    {
        private string check_url     = "http://tlokzz.info/updater/api/update2.php?action=available_updates&local_version=" + Application.ProductVersion + "&app_id=";
        private string download_url  = "http://tlokzz.info/updater/api/download.php?app_id=";
        private string download_path = Application.StartupPath + "\\update.exe";
        private bool successfully_downloaded = false;
        //
        WebClient downloader;
        AppUpdate[] availableUpdates;
        //
        public event updateAvailable doneChecking;

        #region Form

        #region Loading/Closing

        public UpdaterForm(int app_id)
        {
            check_url    += app_id;
            download_url += app_id;
            //
            InitializeComponent();
            //
            downloader = new WebClient();
            downloader.DownloadStringCompleted += new DownloadStringCompletedEventHandler(downloader_DownloadStringCompleted);
            downloader.DownloadFileCompleted += new AsyncCompletedEventHandler(downloader_DownloadFileCompleted);
            //
            this.Opacity = 0.0;
        }

        private void UpdaterForm_Load(object sender, EventArgs e)
        {
            this.Text = Application.ProductName + " - Newer Updates";
            //
            int i = 1;
            foreach (AppUpdate update in availableUpdates)
            {
                richTextBox1.AppendText("Version: " + update.Version.ToString() + " - " + update.postDate.ToLocalTime() + "\r\n");
                int another_i = 1;
                foreach (string change in update.Changes)
                {
                    if ((another_i >= update.Changes.Length) && i >= availableUpdates.Length) { richTextBox1.AppendText(change); }
                    else { richTextBox1.AppendText(change + "\r\n"); }
                    another_i++;
                }
                if (i < availableUpdates.Length) { richTextBox1.AppendText("\r\n"); }
                i++;
            }
            //
            this.Opacity = 1.0;
            //
            downloader.DownloadProgressChanged += new DownloadProgressChangedEventHandler(downloader_DownloadProgressChanged);
            if (!downloader.IsBusy) { downloadUpdateAsync(); }
        }

        private void UpdaterForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            e.Cancel = true;
        }

        #endregion

        #region Other form controls

        private void button1_Click(object sender, EventArgs e)
        {
            switch (button1.Text)
            {
                case "Background":
                    this.Opacity = 0;
                    this.ShowIcon = false;
                    break;
                case "Install":
                    installUpdate();
                    break;
            }
        }

        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            Settings.Show_Updater_Changes = (checkBox1.Checked) ? false : true;
        }

        #endregion

        #endregion

        #region Checking

        public void checkForUpdateAsync()
        {
            downloader.DownloadStringAsync(new Uri(check_url));
        }

        private void downloader_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            if (e.Error != null) { return; }
            //
            string[] apps = Regex.Split(e.Result, ";;");
            availableUpdates = new AppUpdate[apps.Length];
            bool updateAvailable = false;
            int i = 0;
            foreach (string app in apps)
            {
                string[] appParts = app.Split(';');
                try
                {
                    availableUpdates[i] = new AppUpdate(Convert.ToInt32(appParts[0]), Version.Parse(appParts[1]), Regex.Split(appParts[2], "\r\n"), Convert.ToInt32(appParts[3]), DateTime.Parse(appParts[4]));
                    if (availableUpdates[i].Version > Version.Parse(Application.ProductVersion)) { updateAvailable = true; }
                }
                catch (FormatException) { return; }
                i++;
            }
            //
            Array.Reverse(availableUpdates);
            //
            doneChecking(updateAvailable, availableUpdates);
        }

        #endregion

        #region Download

        public void downloadUpdateAsync()
        {
            downloader.DownloadFileAsync(new Uri(download_url), download_path);
        }

        private void downloader_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            toolStripProgressBar1.Value = e.ProgressPercentage;
            toolStripStatusLabel1.Text  = e.ProgressPercentage.ToString() + "%";
        }

        private void downloader_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
        {
            if (e.Error != null) { return; }
            successfully_downloaded = true;
            if (this.Opacity == 1.0) { button1.Text = "Install"; }
            else { installUpdate(); }
        }

        #endregion

        #region Installing

        private bool installUpdate()
        {
            if (!successfully_downloaded) { return false; }
            Process.Start(new ProcessStartInfo(Application.StartupPath + "\\updaterSwitcher.exe", "-source " + '"' + download_path + '"' + " -destination " + '"' + Application.ExecutablePath + '"'));
            Environment.Exit(0);
            return true;
        }

        #endregion
    }

    #region Update object (AppUpdate)

    public class AppUpdate
    {
        private int _app_id;
        private Version _version;
        private string[] _changes;
        private int _downloads;
        private DateTime _post_date;

        public AppUpdate(int app_id_, Version version_, string[] changes_, int downloads_, DateTime post_date_)
        {
            _app_id    = app_id_;
            _version   = version_;
            _changes   = changes_;
            _downloads = downloads_;
            _post_date = post_date_;
        }

        public int appID         { get { return _app_id; } }
        public Version Version   { get { return _version; } }
        public string[] Changes  { get { return _changes; } }
        public int Downloads     { get { return _downloads; } }
        public DateTime postDate { get { return _post_date; } }
    }

    #endregion
}
